Direkt am Rhein in Köln liegt eine der berühmtesten Sehenswürdigkeiten Deutschlands: der Kölner Dom. Erbaut in einem Zeitraum vom 632 (!) Jahren, fertiggestellt 1880. Und ab da gingen auch schon die Renovierungsarbeiten los. Stand heute hat der Dom seit über 100 Jahren nicht einen Tag ohne Baugerüst erlebt. Die Dombauhütte Köln, also die Einrichtung, die für die Renovierung zuständig ist, hat in der deutschen Wikipedia sogar einen eigenen Wikipedia-Artikel.
Szenenwechsel zur Software-Entwicklung: Man hat schon vereinzelt von alten Mainframe-Programmen gehört, die gefühlt bereits seit der Fertigstellung des Kölner Doms laufen und immer noch weiterentwickelt werden. Aber auch für den Großteil der neueren Programme gilt: Wirklich fertig sind sie nicht. Wenn man sich nicht ständig um ein Software-System kümmert, altert es. Bibliotheken und Systeme müssen geupdated, existierendes Verhalten geändert, Bugs gefixt, neue Features hinzugefügt werden.
Das entsprechende Mindset für kontinuierliche Weiterentwicklung
Um hier eine kontinuierliche Weiterentwicklung zu ermöglichen, müssen Entwickler*innen mit dem entsprechenden Mindset tätig sein.
Das fängt damit an, sich darüber bewusst zu werden, dass man an einem System arbeitet, das nie fertig werden wird und nie perfekt sein wird. Nicht nur, was neue Features angeht, auch existierende Bereiche werden immer wieder umgeschrieben werden müssen, um die Wartbarkeit nach wie vor zu ermöglichen.
Das bedeutet auch, dass die Aussage „du schreibst Code weder für den Computer, noch für dich, sondern für den, der es später liest“ nicht unterschätzt werden darf. Das heißt also, dass man sich bei der Lesbarkeit des Codes und der Struktur des Moduls, an dem man gerade arbeitet, immer in die Lage eines Neueinsteigers versetzen sollte, der oder die in ein paar Jahren initial das erste Mal an dieser Stelle im Quellcode vorbeikommt: Versteht man die Benennung der Variablen? Macht die Klasse tatsächlich das, was sie laut Konzept sollte (und nur das)? Passt dieser neue Control Flow zur grundsätzlichen Architektur, oder sind z. B. Zyklen entstanden?
Den Broken-Window-Effekt vermeiden
Gerade bei der Weiterentwicklung gewachsener Systeme kommt man unweigerlich an Stellen vorbei, die einigen Refactoring-Bedarf haben, sich aber nicht so ohne weiteres jetzt schon umbauen lassen. Oft machen sich Entwickler*innen hier das Leben leicht, indem sie neue Funktionalität ohne weitere Qualitätssicherungsmaßnahmen direkt einkippen, da es in dem Bereich der Software „ja dann darauf auch nicht mehr ankommt".
In den seltensten Fällen ist das aber sinnvoll. Wenn der Code nicht eh schon kurzfristig entfernt werden soll (meistens nicht der Fall), macht jede Änderung, die ohne entsprechende Qualitätssicherung wie Testabdeckung, Review o. ä. durchgeführt wurde, weitere Änderungen im Zweifel nur noch schwerer. Es ist also wichtig, darauf zu achten, dass das System durch Änderungen nicht noch unwartbarer wird.
Überspitzt gesagt lässt sich hier sonst ein ähnlicher Effekt beobachten wie bei der Broken-Windows-Theorie in Stadtgebieten: Verfallene Stadtgebiete ziehen bevorzugt Kriminalität und damit noch mehr Verfall an. Software-Bereiche mit schlechtem Code verlocken dazu, hier ebenfalls weniger Sorgfalt bei der Weiterentwicklung walten zu lassen.
Die übliche Warnung vor Big Bang-Umbauten
Dass größere Umbauten an einem System nicht mehr mit einem Big Bang, sondern schrittweise erfolgen sollten, hat sich mittlerweile durchgesetzt. Wenn langwierige Verbesserungen an Architektur und System aber durchgeführt werden, so besteht die Gefahr, dass bestimmte Umbauten auf halber Strecke nicht mehr konsequent fortgeführt werden. In diesem Fall ist es wichtig, solche Bereiche bei der Planung explizit auf dem Schirm zu behalten und dafür zu sorgen, dass diese Umbauten dann auch explizit fertiggestellt werden.
Oft ist es gar keine Frage der Priorisierung, sondern manchmal einfach nur eine Frage der Aufmerksamkeit: wenn man gewisse Umbauten nicht mehr auf dem Schirm hat, werden sie nicht weiter vorangetrieben. Umgekehrt muss man bei manchen Refactorings dafür sorgen, dass man diese auch auf längere Zeit hin auf dem Radar hat und daran weiterentwickeln kann. Sich im Tagesgeschäft mal eine Stunde Zeit nehmen, um Codestellen zu suchen, die für das Refactoring weiter bearbeitet werden müssen, reicht schon, um für den Umbau wieder Fortschritte zu erzielen. Wie bei vielen Themen der Softwareentwicklung liegt der Schlüssel zum Erfolg auch in einer guten (Selbst-)Organisation.
Umgekehrt muss bei manchen Stellen zu Beginn darauf geachtet werden, nicht blind mit dem Umbau zu beginnen. Gerade weil sich manche Änderungen quer durch das System ziehen können, sollte ein Umbau hier am Besten in Abstimmung und im Konsens mit dem gesamten Team geschehen: Es sollte ein gemeinsames Verständnis dafür vorhanden sein, wie der Umbau erfolgen kann und wie das Zielsystem hier aussehen soll. Durch die Abstimmung lassen sich meistens bessere Lösungsalternativen ermitteln. Eine solche Abstimmung ermöglicht es auch, das ein Umbau nicht im Einzelkampfmodus, sondern im Team gemeinsam angegangen werden kann.
Nicht zuletzt birgt ein halbherzig begonnener Umbau die Gefahr, dass man statt einer renovierungsbedürftigen Lösung im System jetzt zwei solche Lösungen hat. Manchmal kann es sinnvoll sein, erstmal noch bei der alten Lösung, auch für neue Codebereiche, zu bleiben, um dafür die Konsistenz im System zu erhöhen (was ja auch wieder positiv auf die Wartbarkeit einzahlt). Ein Entwickler in einem unserer Projekte hat das immer schön mit “Wenn schon Wahnsinn, dann mit Methode” umschrieben.
Engagement, Demut, Empathie
Wir Entwickler*innen sind gerne von unserem Code, unseren Konzepten und unserer Art Code zu schreiben, überzeugt. Gegen gesundes Selbstbewusstsein ist nichts einzuwenden, aber manchmal stände uns ein bisschen Demut auch gut zu Gesicht. Zum Einen ist der Code, den wir heute schreiben, ziemlich sicher bereits der neue Legacy-Code von morgen. Und so sind viele Systeme, die wir heute abwertend als Altlast bezeichnen, damals mit besten Wissen und Gewissen entwickelt worden.
Und auch heute ist keineswegs ausgemacht, welche Art von Programmierstil den Test der Zeit besteht und auch nach objektiven Kriterien später tatsächlich als wartbar angesehen werden kann. Für Umbauten in größeren Maßstab gilt das Gleiche. Ein erster wichtiger Schritt besteht darin, sich in die Lage der anderen Entwickler*innen hineinzuversetzen: Statt “ich räume in deinem Code auf” sollte die Haltung eher sein “Lass uns gemeinsam überlegen, wie wir das System hier verbessern können”. An der Stelle von “das hier ist Mist” sollte “es wird gute Gründe geben, warum es so ist wie es ist” gelten. Und statt “ich weiß, wie das Ganze schlussendlich auszusehen hat” arbeite ich persönlich zumindest lieber mit Leuten, die die Haltung “das Team ist mehr als die Summe seiner Teile” verkörpern.
Viele Entwickler wollen sich mit dem Code, den sie schreiben, gerne verewigen. Gute Arbeit abliefern sollte immer unser Anspruch sein, aber das Ziel muss das Gesamtergebnis sein: Ein Softwaresystem, das trotz seiner Komplexität ständig weiterentwickelt werden kann. Renovierungen gehören hier dazu. Genau wie beim Kölner Dom.